#ifndef __XFAT_H
#define __XFAT_H

#include "xtypes.h"
#include "xdisk.h"

#define CLUSTER_INVALID 0x0FFFFFFF // 无效的簇号

#define DIRITEM_NAME_FREE 0xE5 // 目录项空闲名标记
#define DIRITEM_NAME_END 0x00  // 目录项结束名标记

#define DIRITEM_ATTR_READ_ONLY 0x01 // 目录项属性：只读
#define DIRITEM_ATTR_HIDDEN 0x02    // 目录项属性：隐藏
#define DIRITEM_ATTR_SYSTEM 0x04    // 目录项属性：系统类型
#define DIRITEM_ATTR_VOLUME_ID 0x08 // 目录项属性：卷id
#define DIRITEM_ATTR_DIRECTORY 0x10 // 目录项属性：目录
#define DIRITEM_ATTR_ARCHIVE 0x20   // 目录项属性：归档
#define DIRITEM_ATTR_LONG_NAME 0x0F // 目录项属性：长文件名

// 文件类型
typedef enum _xfile_type
{
    FAT_DIR = 0,  // 目录
    FAT_FILE = 1, // 文件
    FAT_VOL = 2,
} xfile_type_t;

#pragma pack(1)
// 文件系统BPB结构
typedef struct _bpb
{
    uint8_t bs_jmp_boot[3];    // 跳转代码 3Byte
    uint8_t bs_oem_name[8];    // OEM名称
    uint16_t bpb_byts_per_sec; // 每扇区字节数
    uint8_t bpb_sec_per_clus;  // 每簇扇区数
    uint16_t bpb_rsvd_sec_cnt; // 保留区扇区数
    uint8_t bpb_num_fats;      // FAT表项数
    uint16_t bpb_root_ent_cnt; // 根目录项目数
    uint16_t bpb_tot_sec16;    // 总的扇区数
    uint8_t bpb_media;         // 媒体类型
    uint16_t bpb_fat_size16;   // FAT表项大小
    uint16_t bpb_sec_per_trk;  // 每磁道扇区数
    uint16_t bpb_num_heads;    // 磁头数
    uint32_t bpb_hidd_sec;     // 隐藏扇区数
    uint32_t bpb_tot_sec32;    // 总的扇区数
} bpb_t;

// BPB中的FAT32结构
typedef struct _fat32_hdr
{
    uint32_t bpb_fat_size32;  // 单个FAT表占用扇区数
    uint16_t bpb_ext_flags;   // 镜像标志
    uint16_t bpb_fs_ver;      // 版本号
    uint32_t bpb_root_clus;   // 根目录的簇号
    uint16_t bpb_fs_info;     // fsinfo的扇区数
    uint16_t bpb_bk_boot_sec; // 备份扇区
    uint8_t bpb_reserved[12];
    uint8_t bs_drv_num; // 设备号
    uint8_t bs_reserved1;
    uint8_t bs_boot_sig;         // 扩展标记
    uint32_t bs_vol_id;          // 卷标列号
    uint8_t bs_vol_lab[11];      // 卷标名称
    uint8_t bs_file_sys_type[8]; // 文件类型名称
} fat32_hdr_t;

// 完整的DBR类型
typedef struct _dbr
{
    bpb_t bpb;         // BPB结构
    fat32_hdr_t fat32; // FAT32结构
} dbr_t;

// FAT目录项的日期类型
typedef struct _dir_item_date
{
    uint16_t day : 5;            // 日
    uint16_t month : 4;          // 月
    uint16_t year_from_1980 : 7; // 年
} dir_item_date_t;

// FAT目录项的时间类型
typedef struct _dir_item_time
{
    uint16_t second_2 : 5; // 2秒
    uint16_t minute : 6;   // 分
    uint16_t hour : 5;     // 时
} dir_item_time_t;

// 目录项结构
typedef struct _dir_item
{
    uint8_t dir_name[8];               // 文件名
    uint8_t dir_ext_name[3];           // 扩展名
    uint8_t dir_atr;                   // 属性
    uint8_t dir_nt_res;                // ?
    uint8_t dir_crt_time_teenth;       // 创建时间的毫秒
    dir_item_time_t dir_crt_time;      // 创建时间
    dir_item_date_t dir_crt_date;      // 创建日期
    dir_item_date_t dir_last_acc_date; // 最后访问日期
    uint16_t dir_fst_clus_hi;          // 簇号高16为
    dir_item_time_t dir_wrt_time;      // 修改时间
    dir_item_date_t dir_wrt_date;      // 修改日期
    uint16_t dir_fst_clus_lo;          // 簇号低16位
    uint32_t dir_file_size;            // 文件字节大小
} dir_item_t;

// 簇类型
typedef union _cluster32
{
    // FAT表项每个元素只有低28bit有效
    struct
    {
        uint32_t next : 28;    // 下一簇簇号
        uint32_t reserved : 4; // 保留为0
    } s;
    uint32_t v;
} cluster32_t;

#pragma pack()

typedef struct _xfat
{
    uint32_t fat_start_sector;  // FAT表起始扇区
    uint32_t fat_tbl_nr;        // FAT表数量
    uint32_t fat_tbl_sectors;   // 每个FAT表的扇区数
    uint32_t total_sectors;     // 总扇区数
    xdisk_part_t *disk_part;    // 对应的分区信息
    uint32_t sec_per_cluster;   // 每簇扇区数
    uint32_t root_cluster;      // 根目录的簇号
    uint32_t cluster_byte_size; // 每簇字节数
    uint8_t *fat_tbl_buf;       // FAT表项缓冲
} xfat_t;

// 文件结构
typedef struct _xfile
{
    xfat_t *xfat;           // 对应的xfat结构
    uint32_t size;          // 文件大小
    uint16_t attr;          // 文件属性
    xfile_type_t type;      // 文件类型
    uint32_t pos;           // 当前位置
    xfat_err_t err;         // 上一次操作的错误码
    uint32_t start_cluster; // 数据区起始扇区簇号
    uint32_t curr_cluster;  // 当前簇号
} xfile_t;

xfat_err_t is_cluster_valid(uint32_t cluster);
xfat_err_t get_next_cluster(xfat_t *xfat, uint32_t curr_cluster_no, uint32_t *next_cluster_no);
xfat_err_t xfat_open(xfat_t *xfat, xdisk_part_t *xdisk_part);
xfat_err_t read_cluster(xfat_t *xfat, uint8_t *buf, uint32_t start_cluster_num, uint32_t cluster_cnt);

xfat_err_t xfile_open(xfat_t *xfat, xfile_t *file, const char *path);
xfat_err_t xfile_close(xfile_t *file);

#endif /* __XFAT_H */
